home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / enscript.4 / enscript / enscript-1.4.0 / afmlib / afmparse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-24  |  23.2 KB  |  1,019 lines

  1. /* 
  2.  * Parse AFM files.
  3.  * Copyright (c) 1995 Markku Rossi.
  4.  *
  5.  * Author: Markku Rossi <mtr@iki.fi>
  6.  */
  7.  
  8. /*
  9.  * This file is part of the AFM library.
  10.  * 
  11.  * This library is free software; you can redistribute it and/or
  12.  * modify it under the terms of the GNU Library General Public
  13.  * License as published by the Free Software Foundation; either
  14.  * version 2 of the License, or (at your option) any later version.
  15.  *
  16.  * This library is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19.  * Library General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU Library General Public
  22.  * License along with this library; if not, write to the Free
  23.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "afmint.h"
  27. #include "afm.h"
  28.  
  29. /*
  30.  * Definitions.
  31.  */
  32.  
  33. #define ISSPACE(ch) \
  34.   ((ch) == ' ' || (ch) == '\n' || (ch) == '\r' || (ch) == '\t' || (ch) == ';')
  35.  
  36. #define GET_VALUE(typenum) get_type (handle, ctx, (typenum), &node)
  37.  
  38. struct parse_ctx_st
  39. {
  40.   FILE *fp;
  41.   char token[1024];        /* maximum line length is 255, this should be
  42.                    enought */
  43.   unsigned int tokenlen;    /* length of the token */
  44. };
  45.  
  46. typedef struct parse_ctx_st ParseCtx;
  47.  
  48. /*
  49.  * Static variables.
  50.  */
  51.  
  52. /* 
  53.  * The AFM keys.  This array must be kept sorted because keys are
  54.  * searched by using binary search.
  55.  */
  56. static struct keyname_st
  57. {
  58.   char *name;
  59.   AFMKey key;
  60. } keynames[] =
  61. {
  62.   {"Ascender",             kAscender},
  63.   {"Axes",             kAxes},
  64.   {"AxisLabel",         kAxisLabel},
  65.   {"AxisType",             kAxisType},
  66.   {"B",                kB},
  67.   {"BlendAxisTypes",         kBlendAxisTypes},
  68.   {"BlendDesignMap",         kBlendDesignMap},
  69.   {"BlendDesignPositions",     kBlendDesignPositions},
  70.   {"C",                kC},
  71.   {"CC",             kCC},
  72.   {"CH",            kCH},
  73.   {"CapHeight",         kCapHeight},
  74.   {"CharWidth",         kCharWidth},
  75.   {"CharacterSet",         kCharacterSet},
  76.   {"Characters",         kCharacters},
  77.   {"Comment",             kComment},
  78.   {"Descendents",         kDescendents},
  79.   {"Descender",         kDescender},
  80.   {"EncodingScheme",         kEncodingScheme},
  81.   {"EndAxis",             kEndAxis},
  82.   {"EndCharMetrics",         kEndCharMetrics},
  83.   {"EndCompFontMetrics",     kEndCompFontMetrics},
  84.   {"EndComposites",         kEndComposites},
  85.   {"EndDescendent",         kEndDescendent},
  86.   {"EndDirection",         kEndDirection},
  87.   {"EndFontMetrics",         kEndFontMetrics},
  88.   {"EndKernData",         kEndKernData},
  89.   {"EndKernPairs",        kEndKernPairs},
  90.   {"EndMaster",         kEndMaster},
  91.   {"EndMasterFontMetrics",     kEndMasterFontMetrics},
  92.   {"EndTrackKern",         kEndTrackKern},
  93.   {"EscChar",             kEscChar},
  94.   {"FamilyName",         kFamilyName},
  95.   {"FontBBox",             kFontBBox},
  96.   {"FontName",             kFontName},
  97.   {"FullName",             kFullName},
  98.   {"IsBaseFont",         kIsBaseFont},
  99.   {"IsFixedPitch",         kIsFixedPitch},
  100.   {"IsFixedV",             kIsFixedV},
  101.   {"ItalicAngle",         kItalicAngle},
  102.   {"KP",             kKP},
  103.   {"KPH",             kKPH},
  104.   {"KPX",             kKPX},
  105.   {"KPY",             kKPY},
  106.   {"L",                kL},
  107.   {"MappingScheme",         kMappingScheme},
  108.   {"Masters",             kMasters},
  109.   {"MetricsSets",         kMetricsSets},
  110.   {"N",                kN},
  111.   {"Notice",             kNotice},
  112.   {"PCC",             kPCC},
  113.   {"StartAxis",         kStartAxis},
  114.   {"StartCharMetrics",         kStartCharMetrics},
  115.   {"StartCompFontMetrics",     kStartCompFontMetrics},
  116.   {"StartComposites",         kStartComposites},
  117.   {"StartDescendent",         kStartDescendent},
  118.   {"StartDirection",         kStartDirection},
  119.   {"StartFontMetrics",         kStartFontMetrics},
  120.   {"StartKernData",         kStartKernData},
  121.   {"StartKernPairs",        kStartKernPairs},
  122.   {"StartMaster",         kStartMaster},
  123.   {"StartMasterFontMetrics",     kStartMasterFontMetrics},
  124.   {"StartTrackKern",         kStartTrackKern},
  125.   {"TrackKern",         kTrackKern},
  126.   {"UnderlinePosition",     kUnderlinePosition},
  127.   {"UnderlineThickness",     kUnderlineThickness},
  128.   {"VV",            kVV},
  129.   {"VVector",             kVVector},
  130.   {"Version",             kVersion},
  131.   {"W",                kW},
  132.   {"W0",            kW0},
  133.   {"W0X",            kW0X},
  134.   {"W0Y",            kW0Y},
  135.   {"W1",            kW1},
  136.   {"W1X",            kW1X},
  137.   {"W1Y",            kW1Y},
  138.   {"WX",            kWX},
  139.   {"WY",            kWY},
  140.   {"Weight",             kWeight},
  141.   {"WeightVector",         kWeightVector},
  142.   {"XHeight",             kXHeight},
  143.  
  144.   {NULL, 0},
  145. };
  146.  
  147. #define NUM_KEYS (sizeof (keynames) / sizeof (struct keyname_st) - 1)
  148.  
  149. /*
  150.  * Prototypes for static functions.
  151.  */
  152.  
  153. /* Throw parse error <error>.  Never returns. */
  154. static void parse_error __P ((AFMHandle handle, AFMError error));
  155.  
  156. static int get_token __P ((AFMHandle handle, ParseCtx *ctx));
  157. static int get_line_token __P ((AFMHandle handle, ParseCtx *ctx));
  158. static void get_key __P ((AFMHandle handle, ParseCtx *ctx,
  159.               AFMKey *key_return));
  160. static void get_type __P ((AFMHandle handle, ParseCtx *ctx, int type,
  161.                AFMNode *type_return));
  162. static void read_character_metrics __P ((AFMHandle handle, ParseCtx *ctx,
  163.                      AFMFont font));
  164. static void read_kern_pairs __P ((AFMHandle handle, ParseCtx *ctx,
  165.                   AFMFont font));
  166. static void read_track_kerns __P ((AFMHandle handle, ParseCtx *ctx,
  167.                    AFMFont font));
  168. static void read_composites __P ((AFMHandle handle, ParseCtx *ctx,
  169.                   AFMFont font));
  170.  
  171. /*
  172.  * Global functions.
  173.  */
  174.  
  175. void
  176. afm_parse_file (AFMHandle handle, const char *filename, AFMFont font)
  177. {
  178.   AFMKey key;
  179.   AFMNode node;
  180.   ParseCtx context;
  181.   ParseCtx *ctx = &context;
  182.   int wd = 0;            /* Writing direction. */
  183.   int done = 0;
  184.  
  185.   ctx->fp = fopen (filename, "r");
  186.   if (ctx->fp == NULL)
  187.     parse_error (handle, SYSERROR (AFM_ERROR_FILE_IO));
  188.  
  189.   /* Check that file is really an AFM file. */
  190.  
  191.   get_key (handle, ctx, &key);
  192.   if (key != kStartFontMetrics)
  193.     parse_error (handle, AFM_ERROR_NOT_AFM_FILE);
  194.   GET_VALUE (AFM_TYPE_NUMBER);
  195.   font->version = node.u.number;
  196.     
  197.   /* Parse it. */
  198.   while (!done)
  199.     {
  200.       get_key (handle, ctx, &key);
  201.       switch (key)
  202.     {
  203.     case kComment:
  204.       (void) get_line_token (handle, ctx);
  205.       continue;
  206.       break;
  207.  
  208.       /* File structure. */
  209.  
  210.     case kStartFontMetrics:
  211.       GET_VALUE (AFM_TYPE_NUMBER);
  212.       font->version = node.u.number;
  213.       break;
  214.  
  215.     case kEndFontMetrics:
  216.       done = 1;
  217.       break;
  218.       
  219.     case kStartCompFontMetrics:
  220.     case kEndCompFontMetrics:
  221.     case kStartMasterFontMetrics:
  222.     case kEndMasterFontMetrics:
  223.       parse_error (handle, AFM_ERROR_UNSUPPORTED_FORMAT);
  224.       break;
  225.  
  226.       /* Global font information. */
  227.     case kFontName:
  228.       GET_VALUE (AFM_TYPE_STRING);
  229.       font->global_info.FontName = node.u.string;
  230.       break;
  231.  
  232.     case kFullName:
  233.       GET_VALUE (AFM_TYPE_STRING);
  234.       font->global_info.FullName = node.u.string;
  235.       break;
  236.  
  237.     case kFamilyName:
  238.       GET_VALUE (AFM_TYPE_STRING);
  239.       font->global_info.FamilyName = node.u.string;
  240.       break;
  241.  
  242.     case kWeight:
  243.       GET_VALUE (AFM_TYPE_STRING);
  244.       font->global_info.Weight = node.u.string;
  245.       break;
  246.  
  247.     case kFontBBox:
  248.       GET_VALUE (AFM_TYPE_NUMBER);
  249.       font->global_info.FontBBox_llx = node.u.number;
  250.       GET_VALUE (AFM_TYPE_NUMBER);
  251.       font->global_info.FontBBox_lly = node.u.number;
  252.       GET_VALUE (AFM_TYPE_NUMBER);
  253.       font->global_info.FontBBox_urx = node.u.number;
  254.       GET_VALUE (AFM_TYPE_NUMBER);
  255.       font->global_info.FontBBox_ury = node.u.number;
  256.       break;
  257.       
  258.     case kVersion:
  259.       GET_VALUE (AFM_TYPE_STRING);
  260.       font->global_info.Version = node.u.string;
  261.       break;
  262.  
  263.     case kNotice:
  264.       GET_VALUE (AFM_TYPE_STRING);
  265.       font->global_info.Notice = node.u.string;
  266.       break;
  267.  
  268.     case kEncodingScheme:
  269.       GET_VALUE (AFM_TYPE_STRING);
  270.       font->global_info.EncodingScheme = node.u.string;
  271.       break;
  272.  
  273.     case kMappingScheme:
  274.       GET_VALUE (AFM_TYPE_INTEGER);
  275.       font->global_info.MappingScheme = node.u.integer;
  276.       break;
  277.  
  278.     case kEscChar:
  279.       GET_VALUE (AFM_TYPE_INTEGER);
  280.       font->global_info.EscChar = node.u.integer;
  281.       break;
  282.  
  283.     case kCharacterSet:
  284.       GET_VALUE (AFM_TYPE_STRING);
  285.       font->global_info.CharacterSet = node.u.string;
  286.       break;
  287.  
  288.     case kCharacters:
  289.       GET_VALUE (AFM_TYPE_INTEGER);
  290.       font->global_info.Characters = node.u.integer;
  291.       break;
  292.  
  293.     case kIsBaseFont:
  294.       GET_VALUE (AFM_TYPE_BOOLEAN);
  295.       font->global_info.IsBaseFont = node.u.boolean;
  296.       break;
  297.  
  298.     case kVVector:
  299.       GET_VALUE (AFM_TYPE_NUMBER);
  300.       font->global_info.VVector_0 = node.u.number;
  301.       GET_VALUE (AFM_TYPE_NUMBER);
  302.       font->global_info.VVector_1 = node.u.number;
  303.       break;
  304.  
  305.     case kIsFixedV:
  306.       GET_VALUE (AFM_TYPE_BOOLEAN);
  307.       font->global_info.IsFixedV = node.u.boolean;
  308.       break;
  309.  
  310.     case kCapHeight:
  311.       GET_VALUE (AFM_TYPE_NUMBER);
  312.       font->global_info.CapHeight = node.u.number;
  313.       break;
  314.  
  315.     case kXHeight:
  316.       GET_VALUE (AFM_TYPE_NUMBER);
  317.       font->global_info.XHeight = node.u.number;
  318.       break;
  319.  
  320.     case kAscender:
  321.       GET_VALUE (AFM_TYPE_NUMBER);
  322.       font->global_info.Ascender = node.u.number;
  323.       break;
  324.  
  325.     case kDescender:
  326.       GET_VALUE (AFM_TYPE_NUMBER);
  327.       font->global_info.Descender = node.u.number;
  328.       break;
  329.  
  330.       /* Writing directions. */
  331.     case kStartDirection:
  332.       GET_VALUE (AFM_TYPE_INTEGER);
  333.       wd = node.u.integer;
  334.       font->writing_direction_metrics[wd].is_valid = AFMTrue;
  335.       break;
  336.  
  337.     case kUnderlinePosition:
  338.       GET_VALUE (AFM_TYPE_NUMBER);
  339.       font->writing_direction_metrics[wd].UnderlinePosition
  340.         = node.u.number;
  341.       break;
  342.  
  343.     case kUnderlineThickness:
  344.       GET_VALUE (AFM_TYPE_NUMBER);
  345.       font->writing_direction_metrics[wd].UnderlineThickness
  346.         = node.u.number;
  347.       break;
  348.  
  349.     case kItalicAngle:
  350.       GET_VALUE (AFM_TYPE_NUMBER);
  351.       font->writing_direction_metrics[wd].ItalicAngle = node.u.number;
  352.       break;
  353.  
  354.     case kCharWidth:
  355.       GET_VALUE (AFM_TYPE_NUMBER);
  356.       font->writing_direction_metrics[wd].CharWidth_x = node.u.number;
  357.       GET_VALUE (AFM_TYPE_NUMBER);
  358.       font->writing_direction_metrics[wd].CharWidth_y = node.u.number;
  359.       break;
  360.  
  361.     case kIsFixedPitch:
  362.       GET_VALUE (AFM_TYPE_BOOLEAN);
  363.       font->writing_direction_metrics[wd].IsFixedPitch = node.u.boolean;
  364.       break;
  365.  
  366.     case kEndDirection:
  367.       break;
  368.  
  369.       /* Individual Character Metrics. */
  370.     case kStartCharMetrics:
  371.       GET_VALUE (AFM_TYPE_INTEGER);
  372.       font->num_character_metrics = node.u.integer;
  373.       font->character_metrics =
  374.         (AFMIndividualCharacterMetrics *)
  375.           calloc (font->num_character_metrics,
  376.               sizeof (AFMIndividualCharacterMetrics));
  377.       if (font->character_metrics == NULL)
  378.         parse_error (handle, AFM_ERROR_MEMORY);
  379.  
  380.       read_character_metrics (handle, ctx, font);
  381.       break;
  382.  
  383.       /* Kerning Data. */
  384.     case kStartKernData:
  385.       break;
  386.  
  387.     case kStartKernPairs:
  388.       if (font->info_level & AFM_I_KERN_PAIRS)
  389.         {
  390.           GET_VALUE (AFM_TYPE_INTEGER);
  391.           font->num_kern_pairs = node.u.integer;
  392.           font->kern_pairs =
  393.         (AFMPairWiseKerning *) calloc (font->num_kern_pairs,
  394.                            sizeof (AFMPairWiseKerning));
  395.           if (font->kern_pairs == NULL)
  396.         parse_error (handle, AFM_ERROR_MEMORY);
  397.  
  398.           read_kern_pairs (handle, ctx, font);
  399.         }
  400.       else
  401.         {
  402.           do
  403.         {
  404.           (void) get_line_token (handle, ctx);
  405.           get_key (handle, ctx, &key);
  406.         }
  407.           while (key != kEndKernPairs);
  408.         }
  409.       break;
  410.  
  411.     case kStartTrackKern:
  412.       if (font->info_level & AFM_I_TRACK_KERNS)
  413.         {
  414.           GET_VALUE (AFM_TYPE_INTEGER);
  415.           font->num_track_kerns = node.u.integer;
  416.           font->track_kerns
  417.         = (AFMTrackKern *) calloc (font->num_track_kerns,
  418.                        sizeof (AFMTrackKern));
  419.           if (font->track_kerns == NULL)
  420.         parse_error (handle, AFM_ERROR_MEMORY);
  421.  
  422.           read_track_kerns (handle, ctx, font);
  423.         }
  424.       else
  425.         {
  426.           do
  427.         {
  428.           (void) get_line_token (handle, ctx);
  429.           get_key (handle, ctx, &key);
  430.         }
  431.           while (key != kEndTrackKern);
  432.         }
  433.       break;
  434.  
  435.     case kEndKernData:
  436.       break;
  437.  
  438.       /* Composite Character Data. */
  439.     case kStartComposites:
  440.       if (font->info_level & AFM_I_COMPOSITES)
  441.         {
  442.           GET_VALUE (AFM_TYPE_INTEGER);
  443.           font->num_composites = node.u.integer;
  444.           font->composites
  445.         = (AFMComposite *) calloc (font->num_composites,
  446.                        sizeof (AFMComposite));
  447.           if (font->composites == NULL)
  448.         parse_error (handle, AFM_ERROR_MEMORY);
  449.  
  450.           read_composites (handle, ctx, font);
  451.         }
  452.       else
  453.         {
  454.           do
  455.         {
  456.           (void) get_line_token (handle, ctx);
  457.           get_key (handle, ctx, &key);
  458.         }
  459.           while (key != kEndComposites);
  460.         }
  461.       break;
  462.  
  463.     default:
  464.       /* Ignore. */
  465.       break;
  466.     }
  467.     }
  468.   fclose (ctx->fp);
  469.  
  470.   /* Check post conditions. */
  471.   
  472.   if (!font->writing_direction_metrics[0].is_valid
  473.       && !font->writing_direction_metrics[1].is_valid)
  474.     /* No direction specified, 0 implied. */
  475.     font->writing_direction_metrics[0].is_valid = AFMTrue;
  476.  
  477.   /* Undef character. */
  478.   if (!strhash_get (font->private->fontnames, "space", 5,
  479.             (void *) font->private->undef))
  480.     {
  481.       /* Character "space" is not defined.  Select the first one. */
  482.       assert (font->num_character_metrics > 0);
  483.       font->private->undef = &font->character_metrics[0];
  484.     }
  485.  
  486.   /* Fixed pitch. */
  487.   if (font->writing_direction_metrics[0].is_valid
  488.       && font->writing_direction_metrics[0].IsFixedPitch)
  489.     {
  490.       /* Take one, it doesn't matter which one. */
  491.       font->writing_direction_metrics[0].CharWidth_x
  492.     = font->character_metrics[0].w0x;
  493.       font->writing_direction_metrics[0].CharWidth_y
  494.     = font->character_metrics[0].w0y;
  495.     }
  496.   if (font->writing_direction_metrics[1].is_valid
  497.       && font->writing_direction_metrics[1].IsFixedPitch)
  498.     {
  499.       font->writing_direction_metrics[1].CharWidth_x
  500.     = font->character_metrics[1].w1x;
  501.       font->writing_direction_metrics[1].CharWidth_y
  502.     = font->character_metrics[1].w1y;
  503.     }
  504. }
  505.  
  506.  
  507. /*
  508.  * Static functions.
  509.  */
  510.  
  511. static void
  512. parse_error (AFMHandle handle, AFMError error)
  513. {
  514.   handle->parse_error = error;
  515.   longjmp (handle->jmpbuf, 1);
  516.  
  517.   /* If this is reached, then all is broken. */
  518.   fprintf (stderr, "AFM: fatal internal longjmp() error.\n");
  519.   abort ();
  520. }
  521.  
  522.  
  523. static int
  524. get_token (AFMHandle handle, ParseCtx *ctx)
  525. {
  526.   int ch;
  527.   int i;
  528.  
  529.   /* Skip the leading whitespace. */
  530.   while ((ch = getc (ctx->fp)) != EOF)
  531.     if (!ISSPACE (ch))
  532.       break;
  533.  
  534.   if (ch == EOF)
  535.     return 0;
  536.  
  537.   ungetc (ch, ctx->fp);
  538.  
  539.   /* Get name. */
  540.   for (i = 0, ch = getc (ctx->fp);
  541.        i < sizeof (ctx->token) && ch != EOF && !ISSPACE (ch);
  542.        i++, ch = getc (ctx->fp))
  543.     ctx->token[i] = ch;
  544.  
  545.   if (i >= sizeof (ctx->token))
  546.     /* Line is too long, this is against AFM specification. */
  547.     parse_error (handle, AFM_ERROR_SYNTAX);
  548.   
  549.   ctx->token[i] = '\0';
  550.   ctx->tokenlen = i;
  551.  
  552.   return 1;
  553. }
  554.  
  555.  
  556. static int
  557. get_line_token (AFMHandle handle, ParseCtx *ctx)
  558. {
  559.   int i, ch;
  560.   
  561.   /* Skip the leading whitespace. */
  562.   while ((ch = getc (ctx->fp)) != EOF)
  563.     if (!ISSPACE (ch))
  564.       break;
  565.  
  566.   if (ch == EOF)
  567.     return 0;
  568.  
  569.   ungetc (ch, ctx->fp);
  570.  
  571.   /* Read to the end of the line. */
  572.   for (i = 0, ch = getc (ctx->fp);
  573.        i < sizeof (ctx->token) && ch != EOF && ch != '\n';
  574.        i++, ch = getc (ctx->fp))
  575.     ctx->token[i] = ch;
  576.  
  577.   if (i >= sizeof (ctx->token))
  578.     parse_error (handle, AFM_ERROR_SYNTAX);
  579.  
  580.   /* Skip all trailing whitespace. */
  581.   for (i--; i >= 0 && ISSPACE (ctx->token[i]); i--)
  582.     ;
  583.   i++;
  584.  
  585.   ctx->token[i] = '\0';
  586.   ctx->tokenlen = i;
  587.  
  588.   return 1;
  589. }
  590.  
  591.  
  592. static int
  593. match_key (char *key)
  594. {
  595.   int lower = 0;
  596.   int upper = NUM_KEYS;
  597.   int midpoint, cmpvalue;
  598.   AFMBoolean found = AFMFalse;
  599.  
  600.   while ((upper >= lower) && !found)
  601.     {
  602.       midpoint = (lower + upper) / 2;
  603.       if (keynames[midpoint].name == NULL)
  604.     break;
  605.       
  606.       cmpvalue = strcmp (key, keynames[midpoint].name);
  607.       if (cmpvalue == 0)
  608.     found = AFMTrue;
  609.       else if (cmpvalue < 0)
  610.     upper = midpoint - 1;
  611.       else
  612.     lower = midpoint + 1;
  613.     }
  614.  
  615.   if (found)
  616.     return keynames[midpoint].key;
  617.  
  618.   return -1;
  619. }
  620.  
  621.  
  622. static void
  623. get_key (AFMHandle handle, ParseCtx *ctx, AFMKey *key_return)
  624. {
  625.   int key;
  626.  
  627.   while (1)
  628.     {
  629.       if (!get_token (handle, ctx))
  630.     /* Unexpected EOF. */
  631.     parse_error (handle, AFM_ERROR_SYNTAX);
  632.  
  633.       key = match_key (ctx->token);
  634.       if (key >= 0)
  635.     {
  636.       *key_return = key;
  637.       return;
  638.     }
  639.  
  640.       /* No match found.  According to standard, we must skip this key. */
  641.       afm_error (handle, "skipping key \"%s\"", ctx->token);
  642.       get_line_token (handle, ctx);
  643.     }
  644.  
  645.   /* NOTREACHED */
  646. }
  647.  
  648.  
  649. /* Reader for AFM types. */
  650. static void
  651. get_type (AFMHandle handle, ParseCtx *ctx, int type, AFMNode *type_return)
  652. {
  653.   char buf[256];
  654.  
  655.   switch (type)
  656.     {
  657.     case AFM_TYPE_STRING:
  658.       if (!get_line_token (handle, ctx))
  659.     parse_error (handle, AFM_ERROR_SYNTAX);
  660.  
  661.       type_return->u.string = (AFMString) calloc (1, ctx->tokenlen + 1);
  662.       if (type_return->u.string == NULL)
  663.     parse_error (handle, AFM_ERROR_MEMORY);
  664.  
  665.       memcpy (type_return->u.string, ctx->token, ctx->tokenlen);
  666.       break;
  667.  
  668.     case AFM_TYPE_NAME:
  669.       if (!get_token (handle, ctx))
  670.     parse_error (handle, AFM_ERROR_SYNTAX);
  671.  
  672.       type_return->u.name = (AFMName) calloc (1, ctx->tokenlen + 1);
  673.       if (type_return->u.string == NULL)
  674.     parse_error (handle, AFM_ERROR_MEMORY);
  675.  
  676.       memcpy (type_return->u.name, ctx->token, ctx->tokenlen);
  677.       break;
  678.  
  679.     case AFM_TYPE_NUMBER:
  680.       if (!get_token (handle, ctx))
  681.     parse_error (handle, AFM_ERROR_SYNTAX);
  682.  
  683.       memcpy (buf, ctx->token, ctx->tokenlen);
  684.       buf[ctx->tokenlen] = '\0';
  685.       type_return->u.number = atof (buf);
  686.       break;
  687.  
  688.     case AFM_TYPE_INTEGER:
  689.       if (!get_token (handle, ctx))
  690.     parse_error (handle, AFM_ERROR_SYNTAX);
  691.  
  692.       memcpy (buf, ctx->token, ctx->tokenlen);
  693.       buf[ctx->tokenlen] = '\0';
  694.       type_return->u.integer = atoi (buf);
  695.       break;
  696.  
  697.     case AFM_TYPE_ARRAY:
  698.       fprintf (stderr, "Array types not implemented yet.\n");
  699.       abort ();
  700.       break;
  701.  
  702.     case AFM_TYPE_BOOLEAN:
  703.       if (!get_token (handle, ctx))
  704.     parse_error (handle, AFM_ERROR_SYNTAX);
  705.  
  706.       memcpy (buf, ctx->token, ctx->tokenlen);
  707.       buf[ctx->tokenlen] = '\0';
  708.  
  709.       if (strcmp (buf, "true") == 0)
  710.     type_return->u.boolean = AFMTrue;
  711.       else if (strcmp (buf, "false") == 0)
  712.     type_return->u.boolean = AFMFalse;
  713.       else
  714.     parse_error (handle, AFM_ERROR_SYNTAX);
  715.       break;
  716.  
  717.     default:
  718.       fprintf (stderr, "get_type(): illegal type %d\n", type_return->type);
  719.       abort ();
  720.       break;
  721.     }
  722. }
  723.  
  724.  
  725. static void
  726. read_character_metrics (AFMHandle handle, ParseCtx *ctx, AFMFont font)
  727. {
  728.   int i = 0;
  729.   AFMNode node;
  730.   AFMIndividualCharacterMetrics *cm = NULL;
  731.   AFMKey key;
  732.   int done = 0;
  733.   int first = 1;
  734.  
  735.   while (!done)
  736.     {
  737.       get_key (handle, ctx, &key);
  738.       switch (key)
  739.     {
  740.     case kC:
  741.       if (first)
  742.         first = 0;
  743.       else
  744.         i++;
  745.       if (i >= font->num_character_metrics)
  746.         parse_error (handle, AFM_ERROR_SYNTAX);
  747.  
  748.       cm = &font->character_metrics[i];
  749.       GET_VALUE (AFM_TYPE_INTEGER);
  750.       cm->character_code = node.u.integer;
  751.       if (cm->character_code >= 0 && cm->character_code <= 255)
  752.         font->encoding[cm->character_code] = cm;
  753.       break;
  754.  
  755.     case kCH:
  756.       printf ("* CH\n");
  757.       break;
  758.  
  759.     case kWX:
  760.     case kW0X:
  761.       GET_VALUE (AFM_TYPE_NUMBER);
  762.       cm->w0x = node.u.number;
  763.       cm->w0y = 0.0;
  764.       break;
  765.  
  766.     case kW1X:
  767.       GET_VALUE (AFM_TYPE_NUMBER);
  768.       cm->w1x = node.u.number;
  769.       cm->w1y = 0.0;
  770.       break;
  771.  
  772.     case kWY:
  773.     case kW0Y:
  774.       GET_VALUE (AFM_TYPE_NUMBER);
  775.       cm->w0y = node.u.number;
  776.       cm->w0x = 0.0;
  777.       break;
  778.  
  779.     case kW1Y:
  780.       GET_VALUE (AFM_TYPE_NUMBER);
  781.       cm->w1y = node.u.number;
  782.       cm->w1x = 0.0;
  783.       break;
  784.  
  785.     case kW:
  786.     case kW0:
  787.       GET_VALUE (AFM_TYPE_NUMBER);
  788.       cm->w0x = node.u.number;
  789.       GET_VALUE (AFM_TYPE_NUMBER);
  790.       cm->w0y = node.u.number;
  791.       break;
  792.  
  793.     case kW1:
  794.       GET_VALUE (AFM_TYPE_NUMBER);
  795.       cm->w1x = node.u.number;
  796.       GET_VALUE (AFM_TYPE_NUMBER);
  797.       cm->w1y = node.u.number;
  798.       break;
  799.           
  800.     case kVV:
  801.       GET_VALUE (AFM_TYPE_NUMBER);
  802.       cm->vv_x = node.u.number;
  803.       GET_VALUE (AFM_TYPE_NUMBER);
  804.       cm->vv_y = node.u.number;
  805.       break;
  806.           
  807.     case kN:
  808.       GET_VALUE (AFM_TYPE_NAME);
  809.       cm->name = node.u.name;
  810.       if (!strhash_put (font->private->fontnames, cm->name,
  811.                 strlen (cm->name), cm, NULL))
  812.         parse_error (handle, AFM_ERROR_MEMORY);
  813.       break;
  814.           
  815.     case kB:
  816.       GET_VALUE (AFM_TYPE_NUMBER);
  817.       cm->llx = node.u.number;
  818.       GET_VALUE (AFM_TYPE_NUMBER);
  819.       cm->lly = node.u.number;
  820.       GET_VALUE (AFM_TYPE_NUMBER);
  821.       cm->urx = node.u.number;
  822.       GET_VALUE (AFM_TYPE_NUMBER);
  823.       cm->ury = node.u.number;
  824.       break;
  825.           
  826.     case kL:
  827.       /* XXX Skip ligatures. */
  828.       get_line_token (handle, ctx);
  829.       break;
  830.  
  831.     case kEndCharMetrics:
  832.       if (i != font->num_character_metrics - 1)
  833.         {
  834.           /*
  835.            * My opinion is that this is a syntax error; the
  836.            * creator of this AFM file should have been smart
  837.            * enought to count these character metrics.  Well,
  838.            * maybe that is too much asked...
  839.            */
  840.           font->num_character_metrics = i + 1;
  841.         }
  842.  
  843.       done = 1;
  844.       break;
  845.           
  846.     default:
  847.       parse_error (handle, AFM_ERROR_SYNTAX);
  848.       break;
  849.     }
  850.     }
  851. }
  852.  
  853.  
  854. static void
  855. read_kern_pairs (AFMHandle handle, ParseCtx *ctx, AFMFont font)
  856. {
  857.   int i;
  858.   AFMNode node;
  859.   AFMPairWiseKerning *kp;
  860.   AFMKey key;
  861.  
  862.   for (i = 0; i < font->num_kern_pairs; i++)
  863.     {
  864.       kp = &font->kern_pairs[i];
  865.       get_key (handle, ctx, &key);
  866.  
  867.       switch (key)
  868.     {
  869.     case kKP:
  870.     case kKPX:
  871.     case kKPY:
  872.       GET_VALUE (AFM_TYPE_NAME);
  873.       kp->name1 = node.u.name;
  874.  
  875.       GET_VALUE (AFM_TYPE_NAME);
  876.       kp->name2 = node.u.name;
  877.  
  878.       GET_VALUE (AFM_TYPE_NUMBER);
  879.  
  880.       switch (key)
  881.         {
  882.         case kKP:
  883.           kp->kx = node.u.number;
  884.           GET_VALUE (AFM_TYPE_NUMBER);
  885.           kp->ky = node.u.number;
  886.           break;
  887.  
  888.         case kKPX:
  889.           kp->kx = node.u.number;
  890.           kp->ky = 0.0;
  891.           break;
  892.  
  893.         case kKPY:
  894.           kp->ky = node.u.number;
  895.           kp->kx = 0.0;
  896.           break;
  897.  
  898.         default:
  899.           fprintf (stderr, "AFM: fatal corruption\n");
  900.           abort ();
  901.           break;
  902.         }
  903.       break;
  904.  
  905.     case kKPH:
  906.       /* XXX ignore. */
  907.       break;
  908.  
  909.     default:
  910.       parse_error (handle, AFM_ERROR_SYNTAX);
  911.       break;
  912.     }
  913.     }
  914.  
  915.   /* Get end token. */
  916.   get_key (handle, ctx, &key);
  917.   if (key != kEndKernPairs)
  918.     parse_error (handle, AFM_ERROR_SYNTAX);
  919. }
  920.  
  921.  
  922. static void
  923. read_track_kerns (AFMHandle handle, ParseCtx *ctx, AFMFont font)
  924. {
  925.   int i;
  926.   AFMNode node;
  927.   AFMTrackKern *tk;
  928.   AFMKey key;
  929.  
  930.   for (i = 0; i < font->num_kern_pairs; i++)
  931.     {
  932.       tk = &font->track_kerns[i];
  933.       get_key (handle, ctx, &key);
  934.  
  935.       /* TrackKern degree min-ptsize min-kern max-ptrsize max-kern */
  936.  
  937.       if (key != kTrackKern)
  938.     parse_error (handle, AFM_ERROR_SYNTAX);
  939.  
  940.       GET_VALUE (AFM_TYPE_INTEGER);
  941.       tk->degree = node.u.integer;
  942.  
  943.       GET_VALUE (AFM_TYPE_NUMBER);
  944.       tk->min_ptsize = node.u.number;
  945.  
  946.       GET_VALUE (AFM_TYPE_NUMBER);
  947.       tk->min_kern = node.u.number;
  948.  
  949.       GET_VALUE (AFM_TYPE_NUMBER);
  950.       tk->max_ptsize = node.u.number;
  951.  
  952.       GET_VALUE (AFM_TYPE_NUMBER);
  953.       tk->max_kern = node.u.number;
  954.     }
  955.  
  956.   /* Get end token. */
  957.   get_key (handle, ctx, &key);
  958.   if (key != kEndTrackKern)
  959.     parse_error (handle, AFM_ERROR_SYNTAX);
  960. }
  961.  
  962.  
  963. static void
  964. read_composites (AFMHandle handle, ParseCtx *ctx, AFMFont font)
  965. {
  966.   int i, j;
  967.   AFMNode node;
  968.   AFMComposite *cm;
  969.   AFMKey key;
  970.  
  971.   for (i = 0; i < font->num_composites; i++)
  972.     {
  973.       cm = &font->composites[i];
  974.       get_key (handle, ctx, &key);
  975.  
  976.       if (key != kCC)
  977.     parse_error (handle, AFM_ERROR_SYNTAX);
  978.  
  979.       GET_VALUE (AFM_TYPE_NAME);
  980.       cm->name = node.u.name;
  981.  
  982.       /* Create name -> AFMComposite mapping. */
  983.       if (!strhash_put (font->private->compositenames, cm->name,
  984.             strlen (cm->name), cm, NULL))
  985.     parse_error (handle, AFM_ERROR_MEMORY);
  986.  
  987.       GET_VALUE (AFM_TYPE_INTEGER);
  988.       cm->num_components = node.u.integer;
  989.       cm->components
  990.     = (AFMCompositeComponent *) calloc (cm->num_components,
  991.                         sizeof (AFMCompositeComponent));
  992.  
  993.       /* Read composite components. */
  994.       for (j = 0; j < cm->num_components; j++)
  995.     {
  996.       /* Read "PCC". */
  997.       get_key (handle, ctx, &key);
  998.       if (key != kPCC)
  999.         parse_error (handle, AFM_ERROR_SYNTAX);
  1000.  
  1001.       /* Read values. */
  1002.  
  1003.       GET_VALUE (AFM_TYPE_NAME);
  1004.       cm->components[j].name = node.u.name;
  1005.       
  1006.       GET_VALUE (AFM_TYPE_NUMBER);
  1007.       cm->components[j].deltax = node.u.number;
  1008.  
  1009.       GET_VALUE (AFM_TYPE_NUMBER);
  1010.       cm->components[j].deltay = node.u.number;
  1011.     }
  1012.     }
  1013.  
  1014.   /* Get end token. */
  1015.   get_key (handle, ctx, &key);
  1016.   if (key != kEndComposites)
  1017.     parse_error (handle, AFM_ERROR_SYNTAX);
  1018. }
  1019.